package pl.un4giv3n.mightvsmagic.utils;
import static pl.un4giv3n.mightvsmagic.utils.UserUtil.NEAR_EXP;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import pl.un4giv3n.mightvsmagic.entity.Item;
import pl.un4giv3n.mightvsmagic.entity.ItemTemplate;
import pl.un4giv3n.mightvsmagic.entity.ItemType;
import pl.un4giv3n.mightvsmagic.entity.User;
import pl.un4giv3n.mightvsmagic.entity.UserAttribute;
import static pl.un4giv3n.mightvsmagic.utils.UserUtil.NEAR_ATTR;
public final class ItemUtil {
	private ItemUtil() {
	}
	
	public static final int RENAME_COST = 1;
	public static final int SHARPEN_COST = 25;

	@SuppressWarnings("unchecked")
	public static List<ItemTemplate> getAvaibleEq(EntityManager entityManager, User user) {
		Query query = entityManager.createNamedQuery("find.user.avaible.itemtemplates");
		query.setParameter("userAnyExp", Math.max(user.getFightExp(), user.getMagicExp()) + NEAR_EXP); 
		query.setParameter("userMagicExp", user.getMagicExp()+ NEAR_EXP); 
		query.setParameter("userFightExp", user.getFightExp()+ NEAR_EXP); 
		query.setParameter("userParry", UserUtil.getUserSkillLevel(user, UserAttribute.PARRY)+ NEAR_ATTR); 
		query.setParameter("userAttack", UserUtil.getUserSkillLevel(user, UserAttribute.ATTACK)+ NEAR_ATTR); 
		query.setParameter("userMana", UserUtil.getUserSkillLevel(user, UserAttribute.MANA)+ NEAR_ATTR); 
		query.setParameter("userStamina", UserUtil.getUserSkillLevel(user, UserAttribute.STAMINA)+ NEAR_ATTR); 
		query.setParameter("userStrenght", UserUtil.getUserSkillLevel(user, UserAttribute.STRENGHT)+ NEAR_ATTR); 
		List resultList = query.getResultList();
		return resultList;
	}
	
	public static List<Item> getUserEquipedItems(User user){
		List<Item> result = new ArrayList<Item>();
		for (Item item : user.getItems()) {
			if(item.isInUse()){
				result.add(item);
			}
		}
		return result;
	}
	
	public static List<Item> getUserUnequipedItems(User user){
		List<Item> result = new ArrayList<Item>();
		for (Item item : user.getItems()) {
			if(!item.isInUse()){
				result.add(item);
			}
		}
		return result;
	}

	public static boolean matchesItemRequirements(User user, Item item) {
		if(UserUtil.getUserSkillLevel(user, UserAttribute.STAMINA) < item.getStaminaReq()){
			return false;
		}
		if(UserUtil.getUserSkillLevel(user, UserAttribute.STRENGHT) < item.getStrenghtReq()){
			return false;
		}
		if(UserUtil.getUserSkillLevel(user, UserAttribute.MANA) < item.getManaReq()){
			return false;
		}
		if(UserUtil.getUserSkillLevel(user, UserAttribute.ATTACK) < item.getAttackReq()){
			return false;
		}
		if(UserUtil.getUserSkillLevel(user, UserAttribute.PARRY) < item.getParryReq()){
			return false;
		}
		if(item.getRequiredAnyExp() > 0) {
			if(user.getFightExp() < item.getRequiredAnyExp() && user.getMagicExp() < item.getRequiredAnyExp()){
				return false;
			}
		}else{
			if(user.getFightExp() < item.getRequiredFightExp()){
				return false;
			}
			if(user.getMagicExp() < item.getRequiredMagicExp()){
				return false;
			}
		}
		return true;
	}
	public static int getMaxAllowedItemTypes(ItemType type) {
		switch (type) {
			case SWORD1H: 	return 2;
			case SWORD2H: 	return 1;
			case SHIELD: 	return 2;
			case ARMOR: 	return 1;
			case CHARM:  	return 1;
			case RING: 		return 8;
			case WAND1H: 	return 2;
			case WAND2H: 	return 1;
		default:
			throw new IllegalArgumentException("Trying to equip non-existing item type!");
		}
	}

	public static boolean canEquipItemType(User user, ItemType type) {
		if(getUsedItemTypeCount(user, type) < getMaxAllowedItemTypes(type)){
			return true;
		}
		return false;
	}

	/**
	 * @param user
	 * @return additional damage based on used items
	 */
	public static String getItemDamage(final User user) {
		return ItemUtil.getMinItemDamage(user)+" - "+ItemUtil.getMaxItemDamage(user);
	}

	public static double getMaxItemDamage(User user) {
		List<Item> items = user.getItems();
		double dmg = 0;
		for (Item item : items) {
			if (item.isInUse()) {
				dmg += item.getMaxDmg();
			}
		}
		return dmg;
	}

	public static double getMinItemDamage(User user) {
		List<Item> items = user.getItems();
		double dmg = 0;
		for (Item item : items) {
			if (item.isInUse()) {
				dmg += item.getMinDmg();
			}
		}
		return dmg;
	}

	/**
	 * @param user
	 * @return addidtional defense based on used items
	 */
	public static String getItemDefense(final User user) {
		return ItemUtil.getMinItemDefence(user)+" - "+ItemUtil.getMaxItemDefence(user);
	}

	public static double getMaxItemDefence(User user) {
		List<Item> items = user.getItems();
		double dmg = 0;
		for (Item item : items) {
			if (item.isInUse()) {
				dmg += item.getMaxDef();
			}
		}
		return dmg;
	}

	public static double getMinItemDefence(User user) {
		List<Item> items = user.getItems();
		double dmg = 0;
		for (Item item : items) {
			if (item.isInUse()) {
				dmg += item.getMinDef();
			}
		}
		return dmg;
	}

	static int getUsedItemTypeCount(User user, ItemType itemType) {
		List<Item> items = user.getItems();
		int itemCount = 0;
		for (Item item : items) {
			if(item.getType() == itemType && item.isInUse()){
				itemCount++;
			}
		}
		return itemCount;
	}

	public static boolean equipingNotBlockedByOtherItem(User user, Item item) {
		
		ItemType type = item.getType();
		int sword1hCount = getUsedItemTypeCount(user, ItemType.SWORD1H);
		int wand1hCount = getUsedItemTypeCount(user, ItemType.WAND1H);
		int sword2hCount = getUsedItemTypeCount(user, ItemType.SWORD2H);
		int shieldCount = getUsedItemTypeCount(user, ItemType.SHIELD);
		int wand2hCount = getUsedItemTypeCount(user, ItemType.WAND2H);
		switch (type) {
			case SWORD1H: 	//fall throuhg
			case SHIELD: 	//fall throuhg
			case WAND1H: 	
				if(sword2hCount >= 1 || wand2hCount >= 1 || wand1hCount > 1 || sword1hCount > 1 || wand1hCount + sword1hCount >=2 ){ 
					return false;
				}else if (wand1hCount == 1 || sword1hCount == 1){ //this is XOR basing on the above
					if(shieldCount == 0){
						return sword2hCount == 0 && wand2hCount == 0 && wand1hCount+sword1hCount < 2;
					}else {
						return false;						
					}
				}else { //no 1h swords
					if(shieldCount <= 1){
						return true;
					}else { //two shields
						return false;
					}
				}
			case SWORD2H: 
				if(sword2hCount >= getMaxAllowedItemTypes(ItemType.SWORD2H)){
					return false;
				} else {
					return   sword1hCount == 0
					&& shieldCount == 0
					&& wand1hCount == 0
					&& wand2hCount == 0;
				}
			case WAND2H: 	
				if(wand2hCount >= getMaxAllowedItemTypes(ItemType.WAND2H)){
					return false;
				} else {
					return   sword1hCount == 0
					&& shieldCount == 0
					&& wand1hCount == 0
					&& wand2hCount == 0;
				}
			case ARMOR: 	return getUsedItemTypeCount(user, ItemType.ARMOR) < getMaxAllowedItemTypes(ItemType.ARMOR);
			case CHARM:  	return getUsedItemTypeCount(user, ItemType.CHARM) < getMaxAllowedItemTypes(ItemType.CHARM);
			case RING: 		return getUsedItemTypeCount(user, ItemType.RING) < getMaxAllowedItemTypes(ItemType.RING);
		}
		return false;
	}

	public static boolean canBesSharpened(Item item) {
		if(item.isSharpened()){
			return false;
		}else{
			switch(item.getType()){
				case WAND1H:
				case WAND2H:
				case SWORD1H:
				case SWORD2H: return true;
				default: return false;
			}
		}
	}
}
